#include "socketchannel.h"
#include "../coroutine_function.h"
#include <string>
#include <unistd.h>
#include <fcntl.h>
#include "tinyrpc/base/logger/logger.h"
#include "tinyrpc/net/eventloop.h"
#include "tinyrpc/net/coroutine_function.h"
namespace TinyRPC{

// 设置为非阻塞模式
SocketChannel::SocketChannel(int fd,  const INetAddress& peerAddress)
: AbstractChannel(fd)
, m_peerAddress(peerAddress)
, m_inBuf(new Buffer())
, m_outBuf(new Buffer()){

    //::fcntl(m_fd, F_SETFL, O_NONBLOCK);
    setBlock(false);
}



int SocketChannel::receiveFromRemote(){
   
    char buf[1024] = {0};
    int len = 0;
    int sum = 0;
    // 循环读， 直到读完为止
    setBlock(false);
    while (true)
    {
       len = coroutine_read(m_fd, buf, 1024);
       
       if(len < 0 ){
           LOG_ERROR<<"socket read error";
           break;
       }else if (len == 0){
            break;
       }else if(len < 1024){
            sum += len;
            m_inBuf->append(buf, len);
            break;
        // 一次没有读完， 就继续读
       }else if(len >= 1024){
            sum += len;
            m_inBuf->append(buf, len);
       }
    }

    return sum;
}

// 实际从m_inBuf 里面读取
std::string SocketChannel::read(AbstractCodec* codec){
    if(codec == nullptr){
        return m_inBuf->read();
    }else{
        return codec->decode(m_inBuf);
    }
}
void SocketChannel::write(BufferPtr buffer){
 
    int sum = 0;
    // 循环读， 直到读完为止
    //setBlock(true);
    int readableLen = buffer->getReadableLen();
    while (sum < readableLen)
    {
        setBlock(true);
       int len = coroutine_write(m_fd, buffer->charAtReadBegin(), buffer->getReadableLen());
       buffer->addReadIndex(len);
       sum += len;
    }
    setBlock(false);
    deleteEvent(EventLoop::CurrentEventLoop(), WriteEvent);
}



void SocketChannel::write(const std::string & buffer){
 
    int sum = 0;
    //setBlock(true);
    while (sum < buffer.size())
    {
       int len = coroutine_write(m_fd, (const void*) buffer.c_str() + sum, buffer.size()-sum);
       sum += len;
    }
    //setBlock(false);
    deleteEvent(EventLoop::CurrentEventLoop(), WriteEvent);
}

void SocketChannel::write(std::string & buffer, AbstractCodec* codec){
    std::string&  newbuffer = buffer;
    if(codec != nullptr){
        newbuffer = codec->encode(buffer);
    }
    write(newbuffer);
}

SocketChannel::SocketChannel()
:AbstractChannel(socket(AF_INET, SOCK_STREAM, 0)){
    setBlock(false);
}



//connect 时候需要设置成block模式
int SocketChannel::connect(const INetAddress& peerAddress){
    setBlock(true);
    m_peerAddress = peerAddress;
    sockaddr_in addr = peerAddress.getSockAddr();
    socklen_t len = sizeof(addr);
    int ret = coroutine_connect(m_fd, (sockaddr *) &addr, len);
    setBlock(false);
    return ret;
}

SocketChannelPtr Create(){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    SocketChannelPtr ptr(new SocketChannel());

}

}


